#include "includes.h"

extern int last_proposed;
extern struct msg_client_update update_queue;
extern int host_count;
extern struct global_history history;
extern int local_aru;
extern int my_id;
extern int last_installed;
extern int state;

void send_proposal(){

	//DEBUGPRINT("In Send Proposal\n",NULL);
	int seq = last_proposed + 1;
	if(in_global_history(seq)){
		last_proposed++;
		//DEBUGPRINT("-------------------------  Recursing In\n",NULL);
		send_proposal();
	}
	
	//DEBUGPRINT("-*-*-*-*-*-*-*-*-*-*-*-*-*-*  BACK FROM RECURSION\n",NULL);
	
	char* u = NULL;
	
	if(get_global_history_proposal(seq) != NULL){
		//DEBUGPRINT("Case 1: SEQ: %d\n",seq);
		u = get_global_history_proposal(seq);	
	}else if(update_queue_empty()){
		return;
	}else{
		//DEBUGPRINT("Case 3\n",NULL);
		struct msg_client_update *tmp;
		struct list_head *pos, *q;
		if(!list_empty(&update_queue.list)){
		list_for_each_safe(pos, q, &update_queue.list){
			
			//DEBUGPRINT("After Case 3\n",NULL);
			
			if(pos == NULL){
				//DEBUGPRINT("*!*!*!*!*!*!!*!*!*!*!**!*!*!*!*!*!* IT WAS //NULL\n",NULL);
			}
		
			tmp = list_entry(pos, struct msg_client_update, list);
			
			if(tmp != NULL){
				//DEBUGPRINT("POPPING From Queue\n",NULL);
				list_del(pos);
				
				/*
				if(pos->next != NULL)
					pos->next->prev = pos->prev;
				if(pos->prev != NULL)
					pos->prev->next = pos->next;
				*/
				//DEBUGPRINT("POPPING From Queue DONE :%d\n",list_empty(&update_queue.list));
				break;
			}
		}
		}
		
		if(tmp != NULL)
			u = tmp->update;
	}
	
	if(u != NULL){
	//DEBUGPRINT("U Is: %s\n",u);
	struct msg_proposal* prop = create_proposal(my_id,last_installed,seq,u);
	update_data_structures(serialize_proposal(prop));
	last_proposed = seq;
	sync();
	send_to_all(serialize_proposal(prop));
	//DEBUGPRINT("DONE SENDING PROPOSALS\n",NULL);
	}
}

int globally_ordered_ready(int seq){

	//DEBUGPRINT("In GOR\n",NULL);
	struct global_history *tmp;
	struct list_head *pos;
	int count = 0;
	list_for_each(pos, &history.list) {
		tmp = list_entry(pos, struct global_history, list);
		
		if(tmp->seq != seq)
			continue;
		
		struct msg_accept* tmpacc;
		struct list_head *apos;
		list_for_each(apos, &tmp->accepts.list){
			tmpacc = list_entry(apos, struct msg_accept, list);
			
		//DEBUGPRINT("GH Seq: %d  Seq: %d\n",tmpacc->seq,seq);
		//DEBUGPRINT("GH View: %d  Last Proposed: %d\n",tmpacc->view,last_installed);
			
			if(tmpacc->view == last_installed){
				count++;
				//DEBUGPRINT("Have %d, Need %d\n",count,(host_count/2+1));
				if(count >= ((host_count/2) + 1)) {
					return 1;
 				}
			}
		}
	}
	
	return 0;
}

void execute_update(int seq){

	//Find GOU Entry for Seq
	struct global_history* tmp = get_history_entry(seq);
	
	//Save to File
	DEBUGPRINT("EXECUTE: The Order of Update %s is %d\n",tmp->gou->update, seq);
	//Check whether this is one of MY updates
	struct msg_client_update *tmp2 = get_from_pending_updates_message(tmp->gou->update);
	
	if(tmp2 == NULL) return;
	
	update_last_executed(tmp2->client_id, tmp2->timestamp);
	
	int id = tmp2->client_id;
	int socket = get_client_socket(id);
	
	//Report to Client
	if(socket != -1){
		//DEBUGPRINT("About To Send OK To Client\n",NULL);
		send_to_socket(socket,"OK");
		//Remove U from Pending Updates
		
	}
	
	
	if(state == STATE_REG_LEADER){
		//if(local_aru >= 5)
			//exit(0);
		send_proposal();
	}
}

int advance_aru(){
	int i = local_aru + 1;
	while(1){
		//DEBUGPRINT("Looking For Sequence %d\n",i);
		struct global_history* tmp = get_history_entry(i);
		if(tmp->gou != NULL){
			//DEBUGPRINT("Found GOU For %d, SEQ is %d\n",i,tmp->seq);
			if(i == tmp->seq){
				//DEBUGPRINT("Executing Update for %d\n",i);
				execute_update(tmp->seq);
			}
			local_aru++;
			i++;
		}else{
			sync();
			return;
		}
	}
}
